import re
import global_objects as go

def validateNumeric(text):
    """ Validation for the Numeric type """

    pattern = re.compile(r'(\s*numeric\s*)(\(\s*)?(\d+\s*)?(,\s*)?(\d+\s*)?(,\s*)?(\d+\s*)?(,\s*)?(\d+\s*)?(,\s*)?(\d+\s*)?(,\s*)?(\d+\s*)?(,\s*)?([pf]\s*)?(,\s*)?(\w+\.\w+\s*)?(\)\s*)?$')
    m = pattern.match(text)

    if (m):
        # cnostructing list, named "lst" with elements all matched groups
        lst = list(m.groups()[:])

        # validation for parenthesis existance - don't exist
        if (lst[1] == None and lst[17] == None and lst.count(None) == 17):
            return True
        
        # validation for parenthesis existance - exist
        elif (lst[1] != None and lst[17] != None):
            # validation for arguments existance - exit
            if (lst[2] != None or lst[4] != None or lst[6] != None or lst[8] != None or lst[10] != None or lst[12] != None or lst[14] != None or lst[16] != None):
                            
                # number_of_digits specified
                if (lst[2] != None and int(lst[2].strip()) > 0):
                    # min_value specified
                    if (lst[6] != None):
                        # validation with min_value
                        if (int(lst[2].strip()) < len(lst[6].strip())):
                            go.errMessage =  "Invalid numeric format: #digits < min_value"
                            return False
                    # mid_value specified
                    elif (lst[8] != None):
                        #validate with mid_value
                        if (int(lst[2].strip()) < len(lst[8].strip())):
                            go.errMessage =  "Invalid numeric format: #digits < mid_value"
                            return False
                    # max_value specified
                    elif (lst[10] != None):
                        #validate with max_value
                        if (int(lst[2].strip()) > len(lst[10].strip())):
                            go.errMessage =  "Invalid numeric format: #digits > max_value"
                            return False
                    else:
                        pass
                
                # min_value and mid_value specified
                if (lst[6] != None and lst[8] != None):
                    if (int(lst[6].strip()) > int(lst[8].strip())):
                        go.errMessage =  "Invalid numeric format: min_value > mid_value"
                        return False

                # min_value and max_value specified
                if (lst[6] != None and lst[10] != None):
                    if (int(lst[6].strip()) > int(lst[10].strip())):
                        go.errMessage =  "Invalid numeric format: min_value > max_value"
                        return False

                # mid_value and max_value specified
                if (lst[8] != None and lst[10] != None):
                    if (int(lst[8].strip()) > int(lst[10].strip())):
                        go.errMessage =  "Invalid numeric format: mid_value > max_value"
                        return False

                return True

            else:
                return True
        
        else:
            go.errMessage =  "Invalid numeric format: parenthesis missing"
            return False

        
    else:
        go.errMessage =  "Invalid numeric format" 
        return False


def validateString(text):
    """Validation for the String type"""

    pattern = re.compile(r'(\s*string\s*)(\(\s*)?(\d+\s*)?(,\s*)?(\d+\s*)?(,\s*)?([ul]\s*)?(,\s*)?(\[\s*\w*\s*\]\s*)?(\)\s*)?$')
    m = pattern.match(text)

    if (m):
        # cnostructing list, named "lst" with elements all matched groups
        lst = list(m.groups()[:])

        # validation for parenthesis existance - don't exist
        if (lst[1] == None and lst[9] == None and lst.count(None) == 9):
            return True
        
        # validation for parenthesis existance - exist
        elif (lst[1] != None and lst[9] != None):
            # validation for arguments existance - exit
            if (lst[2] != None or lst[4] != None or lst[6] != None or lst[8] != None):

                # min_length and max_length specified
                if (lst[2] != None and lst[4] != None and int(lst[2].strip()) > int(lst[4].strip()) and int(lst[2].strip()) > 0 and int(lst[4].strip()) > 0):
                    go.errMessage =  "Invalid string format: min_length > max_length"
                    return False

                return True

            else:
                return True

        else:
            go.errMessage =  "Invalid string format: parenthesis missing"
            return False
        
    else:
        go.errMessage =  "Invalid string format" 
        return False

def validateDate(text):
    """Validation for the Date type"""

    calendar = [0,31,29,31,30,31,30,31,31,30,31,30,31] 
    MIN_YEAR = '0001'
    MAX_YEAR = '9999'
    f1 = 'YYYY-MM-DD'
    formats = dict(f1 = re.compile(r'(\d\d\d\d)(-)(\d\d)(-)(\d\d)$'))

    pattern = re.compile(r'(\s*date\s*)(\(\s*)?([a-zA-Z-]+\s*)?(,\s*)?([0-9-]+\s*)?(,\s*)?([0-9-]+\s*)?(\)\s*)?$')
    m = pattern.match(text)

    
    if (m):
        # cnostructing list, named "lst" with elements all matched groups
        lst = list(m.groups()[:])

        #return lst

        # validation for parenthesis existance - don't exist
        if (lst[1] == None and lst[7] == None and lst.count(None) == 7):
            return True
        
        # validation for parenthesis existance - exist
        elif (lst[1] != None and lst[7] != None):
            # validation for arguments existance - exit
            if (lst[2] != None or lst[4] != None or lst[6] != None):

                #format specified
                if (lst[2] != None):
                    tmp = [] # container for dates
                    
                    # validation for a correct format
                    if (lst[2].strip() != f1):
                        go.errMessage =  "Invalid date format: wrong format"
                        return False
                    else:
                        # start_date specified
                        if (lst[4] != None):
                            # m1 is the matched object
                            m1 = formats['f1'].match(lst[4].strip())

                            if(m1):
                                # cnostructing list, named "lst1" with elements all matched groups
                                lst1 = list(m1.groups()[:])
                                tmp += lst1

                                # validation for the month
                                if (int(lst1[2]) > 12 or int(lst1[2]) == 0):
                                    go.errMessage =  "Invalid date format: wrong month specified in start_date"
                                    return False

                                # validation for the day
                                elif (int(lst1[4]) > calendar[int(lst1[2])] or int(lst1[4]) == 0):
                                    go.errMessage =  "Invalid date format: wrong day specified in start_date"
                                    return False
                                else:
                                    pass
                            else:
                                go.errMessage =  "Invalid date format: wrong start_date specified"
                                return False
                            
                        # end_date specified
                        if (lst[6] != None):
                            # m2 is the matched object
                            m2 = formats['f1'].match(lst[6].strip())

                            if(m2):
                                # cnostructing list, named "lst2" with elements all matched groups
                                lst2 = list(m2.groups()[:])
                                tmp += lst2

                                # validation for the month
                                if (int(lst2[2]) > 12 or int(lst2[2]) == 0):
                                    go.errMessage =  "Invalid date format: wrong month specified in end_date"
                                    return False

                                # validation for the day
                                elif (int(lst2[4]) > calendar[int(lst2[2])] or int(lst2[4]) == 0):
                                    go.errMessage =  "Invalid date format: wrong day specified in end_date"
                                    return False
                                else:
                                    pass 
                            else:
                                go.errMessage =  "Invalid date format: wrong end_date specified"
                                return False

                        # validation for start_date and end_date if specified
                        if (lst[4] != None and lst[6] != None):

                            if (int(tmp[0]) > int(tmp[5])):
                                go.errMessage =  "Invalid date format: start_date(year) > end_date(year)"
                                return False
                            elif (int(tmp[0]) ==  int(tmp[5]) and int(tmp[2]) > int(tmp[7])):
                                go.errMessage =  "Invalid date format: start_date(month) > end_date(month)"
                                return False
                            elif (int(tmp[0]) ==  int(tmp[5]) and int(tmp[2]) == int(tmp[7]) and int(tmp[4]) > int(tmp[9])):
                                go.errMessage =  "Invalid date format: start_date(day) > end_date(day)"
                                return False
                            else:
                                return True
                        else:
                            return True
                # format not specified
                else:
                    tmp = [] # container for dates
                    
                    # start_date specified
                    if (lst[4] != None):
                        # m1 is the matched object
                        m1 = formats['f1'].match(lst[4].strip())

                        if(m1):
                            # constructing list, named "lst1" with elements all matched groups
                            lst1 = list(m1.groups()[:])
                            tmp += lst1

                            # validation for the month
                            if (int(lst1[2]) > 12 or int(lst1[2]) == 0):
                                go.errMessage =  "Invalid date format: wrong month specified in start_date"
                                return False

                            # validation for the day
                            elif (int(lst1[4]) > calendar[int(lst1[2])] or int(lst1[4]) == 0):
                                go.errMessage =  "Invalid date format: wrong day specified in start_date"
                                return False
                            else:
                                pass
                        else:
                            go.errMessage =  "Invalid date format: wrong start_date specified"
                            return False
                    # end_date specified
                    if (lst[6] != None):
                        # m2 is the matched object
                        m2 = formats['f1'].match(lst[6].strip())

                        if(m2):
                            # constructing list, named "lst2" with elements all matched groups
                            lst2 = list(m2.groups()[:])
                            tmp += lst2

                            # validation for the month
                            if (int(lst2[2]) > 12 or int(lst2[2]) == 0):
                                go.errMessage =  "Invalid date format: wrong month specified in end_date"
                                return False

                            # validation for the day
                            elif (int(lst2[4]) > calendar[int(lst2[2])] or int(lst2[4]) == 0):
                                go.errMessage =  "Invalid date format: wrong day specified in end_date"
                                return False
                            else:
                                pass
                        else:
                            go.errMessage =  "Invalid date format: wrong end_date specified"
                            return False
                        
                    # validation for start_date and end_date
                    if (lst[4] != None and lst[6] != None):

                        if (int(tmp[0]) > int(tmp[5])):
                            go.errMessage =  "Invalid date format: start_date(year) > end_date(year)"
                            return False
                        elif (int(tmp[0]) ==  int(tmp[5]) and int(tmp[2]) > int(tmp[7])):
                            go.errMessage =  "Invalid date format: start_date(month) > end_date(month)"
                            return False
                        elif (int(tmp[0]) ==  int(tmp[5]) and int(tmp[2]) == int(tmp[7]) and int(tmp[4]) > int(tmp[9])):
                            go.errMessage =  "Invalid date format: start_date(day) > end_date(day)"
                            return False
                        else:
                            return True
                    else:
                        return True
                                       
            else:
                return True
            
        else:
            go.errMessage =  "Invalid date format: parenthesis missing"
            return False
        
    else:
        go.errMessage =  "Invalid date format" 
        return False



def validateColumnType(text):

    if ('numeric' in text):
        return validateNumeric(text)
    
    elif ('string' in text):
        return validateString(text)

    elif ('date' in text):
        return validateDate(text)

    else:
        go.errMessage =  "Invalid input format" 
        return False 
